Add support for user atoms and namecalls#48
Merged
natecraddock merged 1 commit intonatecraddock:mainfrom Jan 17, 2024
Merged
Conversation
Owner
natecraddock
left a comment
There was a problem hiding this comment.
The code looks good, but I still don't fully understand the use of user atoms and namecalls, so thank you for working on this 😂
Namecall is a mechanism in Luau to speed up method invocations. The basic idea is that the VM can cache method names (strings) to integer indices the first time it executes a method call. At this point it calls the "user atom callback" with the string. The user callback is responsible for mapping the method string to a unique 16-bit index that's returned to the VM. Next time the VM encounters the same string, it already knows how to map the string to an index as, so it will reuse the user's 16-bit index. The above is the mechanism for quickly resolving function name strings to integers. The other part of the API is using the indices. This part is the __namecall function that's attached to a (userdata) object's metatable. On a method call, the VM knows that the userdata has a registered __namecall, and calls that to dispatch to the actual user's native function to handle the native method. The namecall dispatch routine uses lua.namecallAtom() to retrieve the method name/index, which is used to select which actual native method is called. It's not very simple but it should be fast as the VM doesn't need to do a string->function hash table lookup on every method invocation. I'm not 100% sure of the details, but I suspect that the VM may also patch the bytecode (or some internal representation of it) directly with the namecall indices rather than looking them up from some string hash table.
Contributor
Author
Heh, it is a little complicated. It took some reading and thinking for me to figure it out too. I tried to explain the concept in the (updated) commit message. I did a bit of educated guessing in that writing, but it's probably quite accurate. Hope it makes more sense now. The test case for "namecall" is probably the best document on how to use it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for Luau's faster method invocation protocol that uses a concept called NAMECALL.
When Luau invokes a method with NAMECALL, it sets an interned string pointer into the Lua state struct which can then be quickly turned into either a string or a 16-bit index, for dispatching a user method quickly. This way method calls do not need to lookup methods from a Lua table nor is there any need to do any expensive string comparisons.
Expose some more Luau API to make the above possible. Also adds a couple of convenience functions like
checkVectorandtypeError(used to implementcheckVector, already in lua 5.4 backend).setReadonlyis something the Luau "conformance tests" were using so I added an API for it too. I think it freezing tables to be read-only enables some VM optimizations, but I'm not sure what exactly. It doesn't seem to affect the behavior of my tests in this patch.The
namecallatomis a little tricky to understand as I couldn't find good docs for it. But I think it's usage is fairly apparent from thenamecalltest.I used the same types as in the underying API which means the atom pointers in
toStringAtomandnamecallAtomare*c_int. I guess that's required for the Zig->C calling convention but c_ints are not otherwise used in the API so feel a little out of place.